package router

import (
	"bytes"
	"errors"

	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"

	"gitee.com/liukexing/isrn/model"

	ci "gitee.com/liukexing/isrn/go-libp2p-crypto"
)

var ()

type NodeCyprto struct {
	Pk  ci.PubKey
	Sk  ci.PrivKey
	Rsk ci.RsaPrivateKey
	Rpk ci.RsaPublicKey
}

type RemoteCyprto struct {
	Pk  ci.PubKey
	Rpk ci.RsaPublicKey
}

func (r *RemoteCyprto) UnmarshalPk(pkstr string) (ci.PubKey, error) {
	publicBytes, err := base64.StdEncoding.DecodeString(pkstr)
	if err != nil {
		return nil, err
	}

	return ci.UnmarshalPublicKey(publicBytes)
}

func (r *RemoteCyprto) UnmarshalRpk(rpkstr string) (ci.RsaPublicKey, error) {
	RpubKey := ci.RsaPublicKey{}
	rpublicBytes, err := base64.StdEncoding.DecodeString(rpkstr)
	if err != nil {
		return RpubKey, err
	}

	rpub, err := x509.ParsePKIXPublicKey(rpublicBytes)
	if err != nil {
		return RpubKey, err
	}
	pk, ok := rpub.(*rsa.PublicKey)
	if !ok {
		return RpubKey, errors.New("Not actually an rsa public key.")
	}

	RpubKey.SetK(*pk)
	return RpubKey, nil
}

func (r *RemoteCyprto) BuildSwapInfo(sign string) (*model.KeySwapInfo, error) {
	swapInfo := &model.KeySwapInfo{}
	if pkbytes, err := nodeCyprto.Pk.Bytes(); err != nil {
		return nil, err
	} else {
		swapInfo.Pk = base64.StdEncoding.EncodeToString(pkbytes)
	}
	if rpkbytes, err := ci.MarshalRsaPublicKey(&nodeCyprto.Rpk); err != nil {
		return nil, err
	} else {
		swapInfo.Rpk = base64.StdEncoding.EncodeToString(rpkbytes)
	}
	swapInfo.Sign = sign
	swapInfo.NodeId = nodeid
	return swapInfo, nil
}

//签名
func (r *RemoteCyprto) Sign(data []byte) ([]byte, error) {
	return nodeCyprto.Sk.Sign(data)

}

//校验
func (r *RemoteCyprto) Verify(data []byte, sig []byte) (bool, error) {
	if r.Pk == nil {
		return false, errors.New("Peer Public Key Not Find")
	}
	return r.Pk.Verify(data, sig)
}

//加密
func (r *RemoteCyprto) Encrypt(b []byte) ([]byte, error) {
	if r.Rpk.GetK() == nil {
		return nil, errors.New("Rsa Public Key Not Find")
	}
	partLen := r.Rpk.GetK().N.BitLen()/8 - 11
	chunks := r.split(b, partLen)

	buffer := bytes.NewBufferString("")
	for _, chunk := range chunks {
		bytes, err := r.Rpk.Encrypt(chunk)
		if err != nil {
			return nil, err
		}
		buffer.Write(bytes)
	}

	return buffer.Bytes(), nil
}

//解密
func (r *RemoteCyprto) Decrypt(b []byte) ([]byte, error) {
	partLen := nodeCyprto.Rsk.GetSk().N.BitLen() / 8
	chunks := r.split(b, partLen)

	buffer := bytes.NewBufferString("")
	for _, chunk := range chunks {
		decrypted, err := nodeCyprto.Rsk.Decrypt(chunk)
		if err != nil {
			return nil, err
		}
		buffer.Write(decrypted)
	}

	return buffer.Bytes(), nil
}

//split byte
func (r *RemoteCyprto) split(buf []byte, lim int) [][]byte {
	var chunk []byte
	chunks := make([][]byte, 0, len(buf)/lim+1)
	for len(buf) >= lim {
		chunk, buf = buf[:lim], buf[lim:]
		chunks = append(chunks, chunk)
	}
	if len(buf) > 0 {
		chunks = append(chunks, buf[:len(buf)])
	}
	return chunks
}
